Skip to content

fix(ios): keep active chat, sidebar + Settings sheet across settings changes#4

Merged
boggspa merged 2 commits into
masterfrom
feat/ios-settings-state-preserve
Jun 18, 2026
Merged

fix(ios): keep active chat, sidebar + Settings sheet across settings changes#4
boggspa merged 2 commits into
masterfrom
feat/ios-settings-state-preserve

Conversation

@boggspa

@boggspa boggspa commented Jun 18, 2026

Copy link
Copy Markdown
Owner

Problem

On iOS, changing any setting (theme, composer shell, transcript font, …) reset the workspaces sidebar, unloaded the open chat, re-expanded collapsed section headers, and closed the Settings sheet itself — so you lost your place every time you touched settings.

Root cause

TWThemeStore bumps a @Published revision on every preference change, and RootView keys .id(themes.revision) (AppShell.swift). Because TWTheme tokens are computed statics (not reactive), tearing down + rebuilding the whole tree is how they re-read on a theme change. That teardown wiped the transient @State below it: the open chat, the sidebar expand/collapse Sets, and the Settings sheet's own presentation flag.

Fix (2 commits)

1 — active chat + sidebar (f98f6d24): hoist the transient UI state onto RemoteSessionModel (created above RootView, survives the teardown): selectedTaskId + expandedWorkspaces / collapsedSections / collapsedParents. HomeView reads the Sets via computed properties (call sites unchanged). iPhone navigation becomes selection-driven (navigationDestination(item:) + a Button row) so the open chat re-pushes from the surviving id; iPad already restored via its selection-bound detail column. Bonus: navigationTarget deep-links now push on iPhone too.

2 — Settings sheet (714bda73): the sheet was presented from HomeView (inside the teardown), so it closed on each change. Present it from RootView instead (attached after .id(themes.revision), on the stable outer view) via model.settingsPresented. It stays open across changes and re-themes live through AppSettingsSheet's own @ObservedObject themes — no flash, no internal-state loss.

Result: change theme / composer / font and you stay on your chat, with the sidebar exactly as you left it and the Settings sheet still open.

Verification

  • swift build (package) + 69 Kit tests + iOS app build (iPhone 17 sim) — all green on both commits.
  • Recommended device check: open a chat → open Settings → change theme/composer/font repeatedly → the sheet stays open, the theme updates live, and dismissing returns you to the same chat with the sidebar intact.

Note: this preserves state across the existing teardown (lowest-risk). The deeper follow-up — making TWTheme reactive to drop the .id() teardown entirely (removing the brief re-render flash) — is a large refactor across every token call site. (ConnectedShell.shellMode for files/diff still resets, but Settings isn't reachable from those modes, so it's not hit in practice.)

🤖 Generated with Claude Code

boggspa and others added 2 commits June 18, 2026 10:58
Any settings change (theme, composer shell, transcript font, …) bumps
TWThemeStore.revision, and RootView keys `.id(themes.revision)` — so the
whole tree is torn down/rebuilt to re-read TWTheme's computed-static tokens.
That reset the open chat, collapsed expanded workspaces, and re-expanded
collapsed section headers every time.

Hoist the transient UI state onto RemoteSessionModel (survives the teardown):
selectedTaskId + expandedWorkspaces / collapsedSections / collapsedParents.
HomeView reads the sidebar sets via computed properties (call sites unchanged).
iPhone navigation becomes selection-driven (navigationDestination(item:) + a
Button row instead of NavigationLink) so the open chat re-pushes from the
surviving selectedTaskId after the rebuild; iPad already restores via its
selection-bound detail column. Bonus: navigationTarget deep-links now also
push correctly on iPhone.

Verified: swift build + 69 Kit tests + iOS app build (iPhone 17 sim).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Follow-up to the prior commit. The Settings sheet was presented from
HomeView, inside the `.id(themes.revision)` subtree — so changing a
setting tore it down and closed it (you had to reopen for each change).
Present it from RootView instead (above the teardown) via
model.settingsPresented; it survives the rebuild and re-themes live
through AppSettingsSheet's own @ObservedObject themes — no flash, no
internal-state loss.

Verified: swift build + iOS app build (iPhone 17 sim).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@boggspa boggspa changed the title fix(ios): keep active chat + sidebar state across settings changes fix(ios): keep active chat, sidebar + Settings sheet across settings changes Jun 18, 2026
@boggspa boggspa merged commit c9fc6d2 into master Jun 18, 2026
16 checks passed
boggspa added a commit that referenced this pull request Jun 18, 2026
Build 21 ships the merged iOS work: turn-based guest participation (PR #3,
Mac-side bridge), active-chat/sidebar/Settings-sheet state preservation
across settings changes (PR #4), and surfaced new global/ensemble chat
create failures with retry instead of an infinite spinner (PR #5).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant